πŸ€–πŸ’» Generate Custom Images with Stable DiffusionΒΆ

Time Estimate: 60 minutes

πŸ“‹ OverviewΒΆ

In this activity, you'll gain practical experience using a pre-trained Stable Diffusion model to generate custom images. By exploring how different prompts and parameters affect the generated outputs, you'll develop a deeper understanding of how to guide the generative process effectively. This skill is crucial for roles in creative industries and AI-driven artistry, where visual content is shaped by imaginative and precise prompts.

🎯 Learning Outcomes¢

By the end of this activity, you will be able to:

  • Formulate and refine image generation prompts for Stable Diffusion.
  • Adjust key parameters to influence the artistic direction and quality of generated images.
  • Conduct a comparative analysis of generated outputs to evaluate creativity and fidelity.

πŸ“– ScenarioΒΆ

You are a visual content creator for a digital marketing agency tasked with designing distinctive visuals that captivate audience interest. The agency plans to showcase these visuals during an online campaign. Your challenge is to utilize Stable Diffusion to create a series of striking images based on the creative team's thematic suggestions. Your task includes experimenting with text prompts and generation parameters to align the outputs with the campaign's creative vision.

Task 1: Evaluate Different Prompts [20 minutes]ΒΆ

InΒ [1]:
# imports
from diffusers import StableDiffusionPipeline
import torch
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
AttributeError: 'MessageFactory' object has no attribute 'GetPrototype'
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
AttributeError: 'MessageFactory' object has no attribute 'GetPrototype'

Experiment with a range of text prompts to understand their impact on image creation.

InΒ [2]:
# Set up Stable Diffusion pipeline
model_id = "runwayml/stable-diffusion-v1-5"
device = "cuda" if torch.cuda.is_available() else "cpu"

# Load the pipeline
pipe = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16 if device == "cuda" else torch.float32)
pipe = pipe.to(device)

print(f"Pipeline loaded on {device}")

# Define different prompt styles for testing
prompts = {
    "simple": "A bustling market at dawn with vibrant stalls",
    "abstract": "A whimsical landscape with floating islands and waterfalls",
    "detailed": "A majestic castle on a cliff overlooking a stormy ocean, painted in the style of romantic realism, golden hour lighting, dramatic clouds",
    "artistic": "An ethereal forest spirit dancing among luminescent mushrooms, digital art, fantasy style, soft glowing effects",
    "minimalist": "A single red rose on white background"
}

# Generate images for each prompt style
generated_images = {}
for style, prompt in prompts.items():
    print(f"Generating image for {style} prompt: '{prompt}'")
    
    image = pipe(
        prompt,
        num_inference_steps=20,
        guidance_scale=7.5,
        generator=torch.manual_seed(42)
    ).images[0]
    
    generated_images[style] = image
    
# Display the results
fig, axes = plt.subplots(1, len(prompts), figsize=(20, 4))
for i, (style, image) in enumerate(generated_images.items()):
    axes[i].imshow(image)
    axes[i].set_title(f'{style.capitalize()} Prompt', fontsize=10)
    axes[i].axis('off')

plt.tight_layout()
plt.show()

# Analysis
print("\nπŸ“Š Prompt Analysis:")
print("β€’ Simple prompts produce clear, focused images")
print("β€’ Detailed prompts allow for more artistic control")
print("β€’ Abstract prompts encourage creative interpretation")
print("β€’ Artistic style prompts benefit from specific technique mentions")
model_index.json:   0%|          | 0.00/541 [00:00<?, ?B/s]
Fetching 15 files:   0%|          | 0/15 [00:00<?, ?it/s]
preprocessor_config.json:   0%|          | 0.00/342 [00:00<?, ?B/s]
config.json:   0%|          | 0.00/617 [00:00<?, ?B/s]
merges.txt: 0.00B [00:00, ?B/s]
config.json: 0.00B [00:00, ?B/s]
scheduler_config.json:   0%|          | 0.00/308 [00:00<?, ?B/s]
special_tokens_map.json:   0%|          | 0.00/472 [00:00<?, ?B/s]
safety_checker/model.safetensors:   0%|          | 0.00/1.22G [00:00<?, ?B/s]
text_encoder/model.safetensors:   0%|          | 0.00/492M [00:00<?, ?B/s]
tokenizer_config.json:   0%|          | 0.00/806 [00:00<?, ?B/s]
unet/diffusion_pytorch_model.safetensors:   0%|          | 0.00/3.44G [00:00<?, ?B/s]
vocab.json: 0.00B [00:00, ?B/s]
config.json:   0%|          | 0.00/547 [00:00<?, ?B/s]
config.json:   0%|          | 0.00/743 [00:00<?, ?B/s]
vae/diffusion_pytorch_model.safetensors:   0%|          | 0.00/335M [00:00<?, ?B/s]
Loading pipeline components...:   0%|          | 0/7 [00:00<?, ?it/s]
Pipeline loaded on cuda
Generating image for simple prompt: 'A bustling market at dawn with vibrant stalls'
  0%|          | 0/20 [00:00<?, ?it/s]
Generating image for abstract prompt: 'A whimsical landscape with floating islands and waterfalls'
  0%|          | 0/20 [00:00<?, ?it/s]
Generating image for detailed prompt: 'A majestic castle on a cliff overlooking a stormy ocean, painted in the style of romantic realism, golden hour lighting, dramatic clouds'
  0%|          | 0/20 [00:00<?, ?it/s]
Generating image for artistic prompt: 'An ethereal forest spirit dancing among luminescent mushrooms, digital art, fantasy style, soft glowing effects'
  0%|          | 0/20 [00:00<?, ?it/s]
Generating image for minimalist prompt: 'A single red rose on white background'
  0%|          | 0/20 [00:00<?, ?it/s]
No description has been provided for this image
πŸ“Š Prompt Analysis:
β€’ Simple prompts produce clear, focused images
β€’ Detailed prompts allow for more artistic control
β€’ Abstract prompts encourage creative interpretation
β€’ Artistic style prompts benefit from specific technique mentions

πŸ” Practice

Experiment with different prompt styles and analyze their effects:

  • Test simple prompts like "A bustling market at dawn with vibrant stalls."
  • Try abstract prompts like "A whimsical landscape with floating islands and waterfalls."
  • Compare how prompt specificity affects image generation quality.

βœ… Success Checklist

  • Successfully loaded and configured Stable Diffusion pipeline
  • Generated images using varied prompt styles
  • Documented differences between simple and complex prompts

πŸ’‘ Key Points

  • Use vivid language and specific descriptors to steer the model's interpretation towards a desired theme.
  • The specificity of prompts can significantly alter image output.
  • Prompt engineering is crucial for achieving desired artistic results.

❗ Common Mistakes to Avoid

  • Using vague prompts leading to generic images.
  • Overloading prompts with too many elements, which can confuse the model.
  • Not testing prompt variations to find optimal phrasing.

Task 2: Parameter Exploration [25 minutes]ΒΆ

Adjust key generation parameters to control image output styles.

  1. Experiment with Guidance Scale for prompt adherence vs creative freedom
  2. Test different Seeds to produce varied images from the same prompt
  3. Adjust Steps to balance detail quality with generation time
  4. Document parameter effects on image characteristics
InΒ [3]:
# Select a base prompt for parameter exploration
base_prompt = "A serene mountain lake at sunset with misty forests"

# Test different guidance scales
guidance_scales = [5, 7.5, 10, 15, 20]
guidance_images = []

print("πŸŽ›οΈ Testing Guidance Scale Effects:")
for scale in guidance_scales:
    image = pipe(
        base_prompt,
        num_inference_steps=20,
        guidance_scale=scale,
        generator=torch.manual_seed(42)
    ).images[0]
    guidance_images.append(image)
    print(f"Generated image with guidance scale: {scale}")

# Display guidance scale comparison
fig, axes = plt.subplots(1, len(guidance_scales), figsize=(20, 4))
for i, (scale, image) in enumerate(zip(guidance_scales, guidance_images)):
    axes[i].imshow(image)
    axes[i].set_title(f'Guidance: {scale}', fontsize=10)
    axes[i].axis('off')
plt.suptitle('Effect of Guidance Scale on Image Generation')
plt.tight_layout()
plt.show()

# Test different seeds
seeds = [42, 123, 456, 789, 999]
seed_images = []

print("\n🎲 Testing Seed Variations:")
for seed in seeds:
    image = pipe(
        base_prompt,
        num_inference_steps=20,
        guidance_scale=7.5,
        generator=torch.manual_seed(seed)
    ).images[0]
    seed_images.append(image)
    print(f"Generated image with seed: {seed}")

# Display seed comparison
fig, axes = plt.subplots(1, len(seeds), figsize=(20, 4))
for i, (seed, image) in enumerate(zip(seeds, seed_images)):
    axes[i].imshow(image)
    axes[i].set_title(f'Seed: {seed}', fontsize=10)
    axes[i].axis('off')
plt.suptitle('Effect of Different Seeds on Image Generation')
plt.tight_layout()
plt.show()

# Test different step counts
step_counts = [10, 20, 30, 50]
step_images = []

print("\n⏱️ Testing Inference Steps:")
for steps in step_counts:
    image = pipe(
        base_prompt,
        num_inference_steps=steps,
        guidance_scale=7.5,
        generator=torch.manual_seed(42)
    ).images[0]
    step_images.append(image)
    print(f"Generated image with {steps} steps")

# Display steps comparison
fig, axes = plt.subplots(1, len(step_counts), figsize=(16, 4))
for i, (steps, image) in enumerate(zip(step_counts, step_images)):
    axes[i].imshow(image)
    axes[i].set_title(f'{steps} Steps', fontsize=10)
    axes[i].axis('off')
plt.suptitle('Effect of Inference Steps on Image Quality')
plt.tight_layout()
plt.show()

# Parameter analysis
print("\nπŸ“ˆ Parameter Analysis:")
print("β€’ Guidance Scale 5-10: More creative, diverse outputs")
print("β€’ Guidance Scale 15-20: Stricter prompt adherence, less variation")
print("β€’ Different seeds: Significant composition and detail variations")
print("β€’ More steps: Generally improved detail and coherence")
πŸŽ›οΈ Testing Guidance Scale Effects:
  0%|          | 0/20 [00:00<?, ?it/s]
Generated image with guidance scale: 5
  0%|          | 0/20 [00:00<?, ?it/s]
Generated image with guidance scale: 7.5
  0%|          | 0/20 [00:00<?, ?it/s]
Generated image with guidance scale: 10
  0%|          | 0/20 [00:00<?, ?it/s]
Generated image with guidance scale: 15
  0%|          | 0/20 [00:00<?, ?it/s]
Generated image with guidance scale: 20
No description has been provided for this image
🎲 Testing Seed Variations:
  0%|          | 0/20 [00:00<?, ?it/s]
Generated image with seed: 42
  0%|          | 0/20 [00:00<?, ?it/s]
Generated image with seed: 123
  0%|          | 0/20 [00:00<?, ?it/s]
Generated image with seed: 456
  0%|          | 0/20 [00:00<?, ?it/s]
Generated image with seed: 789
  0%|          | 0/20 [00:00<?, ?it/s]
Generated image with seed: 999
No description has been provided for this image
⏱️ Testing Inference Steps:
  0%|          | 0/10 [00:00<?, ?it/s]
Generated image with 10 steps
  0%|          | 0/20 [00:00<?, ?it/s]
Generated image with 20 steps
  0%|          | 0/30 [00:00<?, ?it/s]
Generated image with 30 steps
  0%|          | 0/50 [00:00<?, ?it/s]
Generated image with 50 steps
No description has been provided for this image
πŸ“ˆ Parameter Analysis:
β€’ Guidance Scale 5-10: More creative, diverse outputs
β€’ Guidance Scale 15-20: Stricter prompt adherence, less variation
β€’ Different seeds: Significant composition and detail variations
β€’ More steps: Generally improved detail and coherence

πŸ” Practice

Systematically explore parameter effects:

  • Keep a record of parameter adjustments and outcomes for accurate comparisons.
  • Test guidance scale values from 5-20 to see prompt adherence changes.
  • Use different seeds with the same prompt to explore creative variations.

βœ… Success Checklist

  • Systematically tested different guidance scale values
  • Generated multiple images with different seeds
  • Experimented with various step counts and documented results

πŸ’‘ Key Points

  • Guidance Scale: Higher values increase prompt adherence; lower values allow creative freedom.
  • Seed: Different seeds produce varied images from identical prompts.
  • Steps: More steps generally improve detail but increase generation time.

❗ Common Mistakes to Avoid

  • Not testing a sufficient range of parameters.
  • Ignoring the interplay of different settings, leading to unintended quality loss.
  • Using extreme parameter values without understanding their effects.

Task 3: Comparative Analysis [15 minutes]ΒΆ

Create a portfolio of images with varied prompts and parameters.

  1. Generate a diverse set of images using different prompt-parameter combinations
  2. Arrange outputs in a visual grid for comparison
  3. Analyze stylistic differences and quality variations
  4. Identify optimal combinations for specific creative goals
InΒ [4]:
# Create a comprehensive portfolio with varied combinations
portfolio_configs = [
    {"prompt": "A cyberpunk cityscape at night", "guidance": 7.5, "steps": 20, "seed": 42},
    {"prompt": "A cyberpunk cityscape at night", "guidance": 15, "steps": 20, "seed": 42},
    {"prompt": "A peaceful zen garden with cherry blossoms", "guidance": 7.5, "steps": 30, "seed": 123},
    {"prompt": "A peaceful zen garden with cherry blossoms", "guidance": 7.5, "steps": 30, "seed": 456},
    {"prompt": "Abstract geometric patterns in vibrant colors", "guidance": 10, "steps": 25, "seed": 789},
    {"prompt": "A majestic dragon flying over mountains", "guidance": 12, "steps": 35, "seed": 999}
]

# Generate portfolio images
portfolio_images = []
portfolio_metadata = []

print("🎨 Generating Portfolio Images:")
for i, config in enumerate(portfolio_configs):
    print(f"Image {i+1}/6: {config['prompt'][:30]}...")
    
    image = pipe(
        config['prompt'],
        num_inference_steps=config['steps'],
        guidance_scale=config['guidance'],
        generator=torch.manual_seed(config['seed'])
    ).images[0]
    
    portfolio_images.append(image)
    portfolio_metadata.append(config)

# Create comprehensive portfolio display
fig, axes = plt.subplots(2, 3, figsize=(18, 12))
axes = axes.flatten()

for i, (image, config) in enumerate(zip(portfolio_images, portfolio_metadata)):
    axes[i].imshow(image)
    title = f"{config['prompt'][:25]}...\nG:{config['guidance']} S:{config['steps']} Seed:{config['seed']}"
    axes[i].set_title(title, fontsize=9)
    axes[i].axis('off')

plt.suptitle('Generated Image Portfolio - Parameter Exploration', fontsize=16)
plt.tight_layout()
plt.show()

# Detailed analysis function
def analyze_image_characteristics(images, configs):
    """Analyze the characteristics of generated images"""
    print("\nπŸ” Portfolio Analysis:")
    print("\n1. Prompt Adherence:")
    for i, config in enumerate(configs):
        adherence = "High" if config['guidance'] >= 12 else "Medium" if config['guidance'] >= 8 else "Low"
        print(f"   Image {i+1}: {adherence} adherence (guidance: {config['guidance']})")
    
    print("\n2. Detail Quality:")
    for i, config in enumerate(configs):
        quality = "High" if config['steps'] >= 30 else "Medium" if config['steps'] >= 20 else "Low"
        print(f"   Image {i+1}: {quality} detail (steps: {config['steps']})")
    
    print("\n3. Creative Diversity:")
    prompt_groups = {}
    for i, config in enumerate(configs):
        base_prompt = config['prompt'][:30]
        if base_prompt in prompt_groups:
            prompt_groups[base_prompt].append(i+1)
        else:
            prompt_groups[base_prompt] = [i+1]
    
    for prompt, image_nums in prompt_groups.items():
        if len(image_nums) > 1:
            print(f"   Images {image_nums}: Variations of '{prompt}...'")

# Run analysis
analyze_image_characteristics(portfolio_images, portfolio_metadata)

# Save portfolio images
print("\nπŸ’Ύ Saving Portfolio Images:")
for i, (image, config) in enumerate(zip(portfolio_images, portfolio_metadata)):
    filename = f"portfolio_image_{i+1}_g{config['guidance']}_s{config['steps']}_seed{config['seed']}.png"
    image.save(filename)
    print(f"Saved: {filename}")

# Final recommendations
print("\n🎯 Recommendations for Creative Work:")
print("β€’ For precise brand imagery: Use guidance scale 12-15")
print("β€’ For creative exploration: Use guidance scale 5-8")
print("β€’ For high detail work: Use 30+ inference steps")
print("β€’ For rapid prototyping: Use 15-20 inference steps")
print("β€’ Always test multiple seeds for prompt variations")
🎨 Generating Portfolio Images:
Image 1/6: A cyberpunk cityscape at night...
  0%|          | 0/20 [00:00<?, ?it/s]
Image 2/6: A cyberpunk cityscape at night...
  0%|          | 0/20 [00:00<?, ?it/s]
Image 3/6: A peaceful zen garden with che...
  0%|          | 0/30 [00:00<?, ?it/s]
Image 4/6: A peaceful zen garden with che...
  0%|          | 0/30 [00:00<?, ?it/s]
Image 5/6: Abstract geometric patterns in...
  0%|          | 0/25 [00:00<?, ?it/s]
Potential NSFW content was detected in one or more images. A black image will be returned instead. Try again with a different prompt and/or seed.
Image 6/6: A majestic dragon flying over ...
  0%|          | 0/35 [00:00<?, ?it/s]
No description has been provided for this image
πŸ” Portfolio Analysis:

1. Prompt Adherence:
   Image 1: Low adherence (guidance: 7.5)
   Image 2: High adherence (guidance: 15)
   Image 3: Low adherence (guidance: 7.5)
   Image 4: Low adherence (guidance: 7.5)
   Image 5: Medium adherence (guidance: 10)
   Image 6: High adherence (guidance: 12)

2. Detail Quality:
   Image 1: Medium detail (steps: 20)
   Image 2: Medium detail (steps: 20)
   Image 3: High detail (steps: 30)
   Image 4: High detail (steps: 30)
   Image 5: Medium detail (steps: 25)
   Image 6: High detail (steps: 35)

3. Creative Diversity:
   Images [1, 2]: Variations of 'A cyberpunk cityscape at night...'
   Images [3, 4]: Variations of 'A peaceful zen garden with che...'

πŸ’Ύ Saving Portfolio Images:
Saved: portfolio_image_1_g7.5_s20_seed42.png
Saved: portfolio_image_2_g15_s20_seed42.png
Saved: portfolio_image_3_g7.5_s30_seed123.png
Saved: portfolio_image_4_g7.5_s30_seed456.png
Saved: portfolio_image_5_g10_s25_seed789.png
Saved: portfolio_image_6_g12_s35_seed999.png

🎯 Recommendations for Creative Work:
β€’ For precise brand imagery: Use guidance scale 12-15
β€’ For creative exploration: Use guidance scale 5-8
β€’ For high detail work: Use 30+ inference steps
β€’ For rapid prototyping: Use 15-20 inference steps
β€’ Always test multiple seeds for prompt variations

πŸ” Practice

Analyze your generated portfolio:

  • Arrange images in a visual grid or sequence for easy comparison.
  • Consider making use of visualization tools to assemble comparisons effectively.
  • Evaluate which combinations work best for different creative objectives.

βœ… Success Checklist

  • Created a diverse portfolio of generated images
  • Organized outputs in a clear comparative format
  • Analyzed stylistic differences and identified optimal parameter combinations

πŸ’‘ Key Points

  • Systematic comparison reveals patterns in parameter effects.
  • Visual organization helps identify successful prompt-parameter combinations.
  • Portfolio analysis guides future creative decisions.

❗ Common Mistakes to Avoid

  • Creating too few variations for meaningful comparison.
  • Not documenting the parameters used for each generated image.
  • Focusing only on technical quality without considering creative merit.

πŸš€ Next Steps

Explore deploying your generated images in real-world marketing campaigns or portfolio showcases to demonstrate the impact of AI-assisted design. Continue to experiment with more complex models and integrate them into other creative workflows for advanced mastery.

πŸ’» Exemplar SolutionΒΆ

Click HERE to see an exemplar solution

Task 1 SolutionΒΆ

# Set up Stable Diffusion pipeline
model_id = "runwayml/stable-diffusion-v1-5"
device = "cuda" if torch.cuda.is_available() else "cpu"

# Load the pipeline
pipe = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16 if device == "cuda" else torch.float32)
pipe = pipe.to(device)

print(f"Pipeline loaded on {device}")

# Define different prompt styles for testing
prompts = {
    "simple": "A bustling market at dawn with vibrant stalls",
    "abstract": "A whimsical landscape with floating islands and waterfalls",
    "detailed": "A majestic castle on a cliff overlooking a stormy ocean, painted in the style of romantic realism, golden hour lighting, dramatic clouds",
    "artistic": "An ethereal forest spirit dancing among luminescent mushrooms, digital art, fantasy style, soft glowing effects",
    "minimalist": "A single red rose on white background"
}

# Generate images for each prompt style
generated_images = {}
for style, prompt in prompts.items():
    print(f"Generating image for {style} prompt: '{prompt}'")
    
    image = pipe(
        prompt,
        num_inference_steps=20,
        guidance_scale=7.5,
        generator=torch.manual_seed(42)
    ).images[0]
    
    generated_images[style] = image
    
# Display the results
fig, axes = plt.subplots(1, len(prompts), figsize=(20, 4))
for i, (style, image) in enumerate(generated_images.items()):
    axes[i].imshow(image)
    axes[i].set_title(f'{style.capitalize()} Prompt', fontsize=10)
    axes[i].axis('off')

plt.tight_layout()
plt.show()

# Analysis
print("\nπŸ“Š Prompt Analysis:")
print("β€’ Simple prompts produce clear, focused images")
print("β€’ Detailed prompts allow for more artistic control")
print("β€’ Abstract prompts encourage creative interpretation")
print("β€’ Artistic style prompts benefit from specific technique mentions")

Task 2 SolutionΒΆ

# Select a base prompt for parameter exploration
base_prompt = "A serene mountain lake at sunset with misty forests"

# Test different guidance scales
guidance_scales = [5, 7.5, 10, 15, 20]
guidance_images = []

print("πŸŽ›οΈ Testing Guidance Scale Effects:")
for scale in guidance_scales:
    image = pipe(
        base_prompt,
        num_inference_steps=20,
        guidance_scale=scale,
        generator=torch.manual_seed(42)
    ).images[0]
    guidance_images.append(image)
    print(f"Generated image with guidance scale: {scale}")

# Display guidance scale comparison
fig, axes = plt.subplots(1, len(guidance_scales), figsize=(20, 4))
for i, (scale, image) in enumerate(zip(guidance_scales, guidance_images)):
    axes[i].imshow(image)
    axes[i].set_title(f'Guidance: {scale}', fontsize=10)
    axes[i].axis('off')
plt.suptitle('Effect of Guidance Scale on Image Generation')
plt.tight_layout()
plt.show()

# Test different seeds
seeds = [42, 123, 456, 789, 999]
seed_images = []

print("\n🎲 Testing Seed Variations:")
for seed in seeds:
    image = pipe(
        base_prompt,
        num_inference_steps=20,
        guidance_scale=7.5,
        generator=torch.manual_seed(seed)
    ).images[0]
    seed_images.append(image)
    print(f"Generated image with seed: {seed}")

# Display seed comparison
fig, axes = plt.subplots(1, len(seeds), figsize=(20, 4))
for i, (seed, image) in enumerate(zip(seeds, seed_images)):
    axes[i].imshow(image)
    axes[i].set_title(f'Seed: {seed}', fontsize=10)
    axes[i].axis('off')
plt.suptitle('Effect of Different Seeds on Image Generation')
plt.tight_layout()
plt.show()

# Test different step counts
step_counts = [10, 20, 30, 50]
step_images = []

print("\n⏱️ Testing Inference Steps:")
for steps in step_counts:
    image = pipe(
        base_prompt,
        num_inference_steps=steps,
        guidance_scale=7.5,
        generator=torch.manual_seed(42)
    ).images[0]
    step_images.append(image)
    print(f"Generated image with {steps} steps")

# Display steps comparison
fig, axes = plt.subplots(1, len(step_counts), figsize=(16, 4))
for i, (steps, image) in enumerate(zip(step_counts, step_images)):
    axes[i].imshow(image)
    axes[i].set_title(f'{steps} Steps', fontsize=10)
    axes[i].axis('off')
plt.suptitle('Effect of Inference Steps on Image Quality')
plt.tight_layout()
plt.show()

# Parameter analysis
print("\nπŸ“ˆ Parameter Analysis:")
print("β€’ Guidance Scale 5-10: More creative, diverse outputs")
print("β€’ Guidance Scale 15-20: Stricter prompt adherence, less variation")
print("β€’ Different seeds: Significant composition and detail variations")
print("β€’ More steps: Generally improved detail and coherence")

Task 3 SolutionΒΆ

# Create a comprehensive portfolio with varied combinations
portfolio_configs = [
    {"prompt": "A cyberpunk cityscape at night", "guidance": 7.5, "steps": 20, "seed": 42},
    {"prompt": "A cyberpunk cityscape at night", "guidance": 15, "steps": 20, "seed": 42},
    {"prompt": "A peaceful zen garden with cherry blossoms", "guidance": 7.5, "steps": 30, "seed": 123},
    {"prompt": "A peaceful zen garden with cherry blossoms", "guidance": 7.5, "steps": 30, "seed": 456},
    {"prompt": "Abstract geometric patterns in vibrant colors", "guidance": 10, "steps": 25, "seed": 789},
    {"prompt": "A majestic dragon flying over mountains", "guidance": 12, "steps": 35, "seed": 999}
]

# Generate portfolio images
portfolio_images = []
portfolio_metadata = []

print("🎨 Generating Portfolio Images:")
for i, config in enumerate(portfolio_configs):
    print(f"Image {i+1}/6: {config['prompt'][:30]}...")
    
    image = pipe(
        config['prompt'],
        num_inference_steps=config['steps'],
        guidance_scale=config['guidance'],
        generator=torch.manual_seed(config['seed'])
    ).images[0]
    
    portfolio_images.append(image)
    portfolio_metadata.append(config)

# Create comprehensive portfolio display
fig, axes = plt.subplots(2, 3, figsize=(18, 12))
axes = axes.flatten()

for i, (image, config) in enumerate(zip(portfolio_images, portfolio_metadata)):
    axes[i].imshow(image)
    title = f"{config['prompt'][:25]}...\nG:{config['guidance']} S:{config['steps']} Seed:{config['seed']}"
    axes[i].set_title(title, fontsize=9)
    axes[i].axis('off')

plt.suptitle('Generated Image Portfolio - Parameter Exploration', fontsize=16)
plt.tight_layout()
plt.show()

# Detailed analysis function
def analyze_image_characteristics(images, configs):
    """Analyze the characteristics of generated images"""
    print("\nπŸ” Portfolio Analysis:")
    print("\n1. Prompt Adherence:")
    for i, config in enumerate(configs):
        adherence = "High" if config['guidance'] >= 12 else "Medium" if config['guidance'] >= 8 else "Low"
        print(f"   Image {i+1}: {adherence} adherence (guidance: {config['guidance']})")
    
    print("\n2. Detail Quality:")
    for i, config in enumerate(configs):
        quality = "High" if config['steps'] >= 30 else "Medium" if config['steps'] >= 20 else "Low"
        print(f"   Image {i+1}: {quality} detail (steps: {config['steps']})")
    
    print("\n3. Creative Diversity:")
    prompt_groups = {}
    for i, config in enumerate(configs):
        base_prompt = config['prompt'][:30]
        if base_prompt in prompt_groups:
            prompt_groups[base_prompt].append(i+1)
        else:
            prompt_groups[base_prompt] = [i+1]
    
    for prompt, image_nums in prompt_groups.items():
        if len(image_nums) > 1:
            print(f"   Images {image_nums}: Variations of '{prompt}...'")

# Run analysis
analyze_image_characteristics(portfolio_images, portfolio_metadata)

# Save portfolio images
print("\nπŸ’Ύ Saving Portfolio Images:")
for i, (image, config) in enumerate(zip(portfolio_images, portfolio_metadata)):
    filename = f"portfolio_image_{i+1}_g{config['guidance']}_s{config['steps']}_seed{config['seed']}.png"
    image.save(filename)
    print(f"Saved: {filename}")

# Final recommendations
print("\n🎯 Recommendations for Creative Work:")
print("β€’ For precise brand imagery: Use guidance scale 12-15")
print("β€’ For creative exploration: Use guidance scale 5-8")
print("β€’ For high detail work: Use 30+ inference steps")
print("β€’ For rapid prototyping: Use 15-20 inference steps")
print("β€’ Always test multiple seeds for prompt variations")